package com.cskaoyan.javase.array._3exception._4operation._3crud;

import javax.xml.transform.sax.SAXTransformerFactory;
import java.util.Arrays;
import java.util.Scanner;

/**
 * 数组元素的增删改查
 * 数组是一个容器，可以用存放元素，存放数据。
 *
 * 在实际开发中，工程中也会需要存放大量数据，这一般是通过数据库来实现的。
 * 实际开发的基本需求就是基于数据库的，对数据进行增删改查，即"crud"，
 * 也有很多中低级Java程序员自嘲自己为"crud工程师"。
 * 当然"crud"指的是：
 *          c，create：新增数据/增加。
 *          r，retrieve：检索数据/查询。
 *          u，update：更新数据/修改。
 *          d，delete ：删除数据/删除。
 *
 * 我们现在还没有学习过数据库，但是不重要。现在我们使用数组这个容器，来模拟数据库
 * 实现日常开发中最常见的"crud"操作。
 *
 * 现在我们使用一个String类型数组来存放学生的姓名,实现对学生姓名数组的增删改查
 * 注: 数组中的名字具有唯一性!
 *
 * @since 16:35
 * @author wuguidong@cskaoyan.onaliyun.com
 */
public class Demo {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        String[] names = new String[10];
        names[0] = "马云";
        names[1] = "马化腾";
        names[2] = "蔡徐坤";
        names[3] = "吴亦凡";
        names[4] = "杨超越";
        printRealNames(names);
        System.out.println("现在开始新增插入一个学生姓名!");
        System.out.println("请输入要插入的学生姓名:");
        String nameInsert = sc.nextLine();
        switch (createName(names, nameInsert)) {
            case 0:
                System.out.println("插入成功!");
                printRealNames(names);
                break;
            case 1:
                System.out.println("插入失败,数组已满!");
                printRealNames(names);
                break;
            case 2:
                System.out.println("插入失败,姓名冲突!");
                printRealNames(names);
                break;
        }
        System.out.println("----------------");
        System.out.println("现在开始删除一个学生姓名!");
        System.out.println("请输入要删除的学生姓名:");
        String nameDelete = sc.nextLine();
        if (deleteName(names, nameDelete)) {
            // 删除成功
            System.out.println("删除成功!");
            printRealNames(names);
        } else {
            System.out.println("删除失败,没有找到目标元素!");
            printRealNames(names);
        }
        System.out.println("------------------");
        System.out.println("现在开始修改一个学生姓名!");
        System.out.println("请输入要修改的学生姓名:");
        String nameUpdate = sc.nextLine();
        System.out.println("请输入要修改后的学生姓名:");
        String newName = sc.nextLine();
        if (updateName(names, nameUpdate, newName)) {
            System.out.println("修改成功!");
            printRealNames(names);
        } else {
            System.out.println("修改失败,无此姓名!");
            printRealNames(names);
        }

        System.out.println("------------------");
        System.out.println("现在开始查找一个学生姓名!");
        System.out.println("请输入要查找的学生姓名:");
        String nameRetrieve = sc.nextLine();
        int targetIndex = retrieveName(names, nameRetrieve);
        if (targetIndex == -1) {
            System.out.println("没找到目标元素");
        } else {
            System.out.println("找到了目标元素,目标元素的下标是:" + targetIndex);
        }

    }

    /*
        学生姓名数组元素的展示,要求去除掉数组中的null元素,仅展示有效元素
        分析:
            1.遍历数组
            2.判断如果数组中的元素是null,直接跳过它
            3.不是null的元素,直接打印
     */
    public static void printRealNames(String[] names) {
        System.out.print("[");
        for (String name : names) {
            if (name == null) {
                // 是null的元素,直接跳过
                continue;
            }
            // 不是null的元素就直接输出
            System.out.print(name + ", ");
        }
        System.out.println("\b\b]");
    }

    // 学生姓名数组的增加,新增一个学生姓名
    /*
        新增一个学生姓名,指的是将原先数组中为null的位置,替换成一个新的String对象
        并且要注意学生姓名具有唯一性,如果添加一个已存在的学生姓名,会添加失败
        所以这个添加学生姓名的方法有以下结果:
            1.数组有空间,且名字不重复,添加成功
            2.数组没有null空间了,数组满了,添加失败
            3.添加的元素已经存在了,添加失败
       这种具有多种结果的方法,我们可以考虑返回一个状态码来指示不同的状态.
       这里我们直接使用一个int值来表示不同的状态:
            1.添加成功,返回0
            2.数组满了,返回1
            3.姓名冲突,返回2
     */

    /**
     * 将一个学生姓名添加进学生数组,结果有三种:
     *      1,添加成功,返回0
     *      2.数组满了,返回1
     *      3.姓名冲突,返回2
     * @param names 被添加进数组中的name
     * @return int
     * @author wuguidong@cskaoyan.onaliyun.com
     * @since 2022/04/14 16:48
     */
    public static int createName(String[] names, String nameInsert) {
        // 1.先判断姓名冲突,遍历学生姓名数组
        for (String name : names) {
            /*
                String的equals方法需要一个String对象来调用这个方法
                如果这个String对象不存在,是一个null
                这时null来调用方法就会出现空指针异常

                怎么解决呢?
                    最简单直接,最通用的方法是判断null,然后跳过
                equals方法的独特解决方案:
                    equals方法需要一个String对象来调用它,也需要传入一个String对象作比较
                    而且equals方法具有对称性
                    左边和右边比,右边和左边比较,结果是一样的?
                    这就要求我们在使用String的equals方法的时候
                        尽量使用一个绝对不可能为null的String引用来调用这个方法
                        或者直接用一个字符串常量来调用这个方法
                        这是一种避免空指针异常,非常好的解决方法
                    这个方法中,nameInsert是键盘录入得到的,肯定不是null
                    所以用它调用方法会更好,永远没有空指针异常
             */
            /*if (name == null){
                continue;
            }*/
            if (nameInsert.equals(name)) {
                // 说明冲突了
                return 2;
            }
        }

        // 2.既然名字不冲突,那就找到一个null的位置,插入它(插入实际上是赋值)
        for (int i = 0; i < names.length; i++) {
            if (names[i] == null) {
                // 找null的位置,然后赋值,相当于插入一个姓名
                names[i] = nameInsert;
                return 0;
            }
        }
        // 数组满了
        return 1;
    }


    // 删除数组中的元素
    /*
        删除数组元素,不是真正的删除,而是将它置为null,也是赋值
        分析这个方法的结果:
            1.找到目标姓名,删除成功
            2.找不到目标姓名,删除失败
        所以该方法的结果具有二元性,返回值可以使用布尔类型
     */

    /**
     * 删除姓名
     * 返回true表示删除成功
     * 否则删除失败
     * @param names 被删除的目标姓名数组
     * @param nameDelete 被删除的目标姓名
     * @return boolean
     * @author wuguidong@cskaoyan.onaliyun.com
     * @since 2022/04/14 17:30
     */
    public static boolean deleteName(String[] names, String nameDelete) {
        // 遍历找到目标元素,然后赋值为null
        for (int i = 0; i < names.length; i++) {
            if (nameDelete.equals(names[i])) {
                // 找到了,置为null,删除成功
                names[i] = null;
                return true;
            }
        }
        // 没有找到,删除失败
        return false;
    }

    // 修改
    public static boolean updateName(String[] names, String nameUpdate, String newName) {
        // 遍历找到目标元素,然后赋值为新的取值
        for (int i = 0; i < names.length; i++) {
            if (nameUpdate.equals(names[i])) {
                // 找到了,赋值,更新成功
                names[i] = newName;
                return true;
            }
        }
        // 没有找到,更新失败
        return false;
    }

    // 查
    /*
        查找数组中的目标元素,然后返回它的下标
     */

    /**
     * 查找元素,找到了就返回下标
     * 没找到就返回-1
     * @param names 被查找元素的目标数组
     * @param nameRetrieve 要查找的目标元素
     * @return int
     * @author wuguidong@cskaoyan.onaliyun.com
     * @since 2022/04/14 17:39
     */
    public static int retrieveName(String[] names, String nameRetrieve) {
        int targetIndex = -1;
        for (int i = 0; i < names.length; i++) {
            if (nameRetrieve.equals(names[i])) {
                // 找到了,赋值
                targetIndex = i;
            }
        }
        // 没找到就返回原始值-1
        return targetIndex;
    }

}
